﻿using System;
using System.Collections;
using System.Configuration;
using System.Data.Linq;
using System.Data.Linq.Mapping;
using System.Linq;
using System.Reflection;
using System.Web;
using Portal.Data.Helper;
using Portal.Core.Helper;

namespace Portal.Data.Entity
{
    public interface IBaseObject
    {
        void Save();
        void Update();
        bool Delete();
    }
    [Serializable]
    public class BaseObject : ICloneable
    {
        public object OriginalData;

        public const int PageSizeDefault = 20;
        public const int PageSize50 = 50;
        public virtual void Save()
        {
            BeforeSaveUpdate();
            ORMHelper.Instance.Save(this);
            AfterSaveUpdate();
        }
        public virtual void Update()
        {
            BeforeSaveUpdate();
            ORMHelper.Instance.Update(this);
            AfterSaveUpdate();
        }
        public virtual void Delete()
        {
            BeforeDelete();
            ORMHelper.Instance.Delete(this);
            AfterDelete();
        }

        public virtual void SaveWithoutPermission()
        {
            BeforeSaveUpdate();
            ORMHelper.InstanceIgnorePermission.Save(this);
            AfterSaveUpdate();
        }
        public virtual void UpdateWithoutPermission()
        {
            BeforeSaveUpdate();
            ORMHelper.InstanceIgnorePermission.Update(this);
            AfterSaveUpdate();
        }
        public virtual void DeleteWithoutPermission()
        {
            BeforeDelete();
            ORMHelper.InstanceIgnorePermission.Delete(this);
            AfterDelete();
        }

        public virtual void BeforeSaveUpdate()
        {

        }
        public virtual void AfterSaveUpdate()
        {

        }
        public virtual void BeforeDelete()
        {

        }
        public virtual void AfterDelete()
        {

        }

        private static bool IsPositiveNumber(object objectid)
        {
            try
            {
                Int64 val = Convert.ToInt64(objectid);
                return val > 0;
            }
            catch { }
            return false;
        }

        public static T FindByPrimaryKey<T>(object objectid, bool forceWithouCache = false) where T : class
        {
            if (!IsPositiveNumber(objectid)) return null;
            var type = typeof(T);
            var parameter = new[] { type.Name, "FindByPrimaryKey", objectid };

            if (!forceWithouCache)
            {
                //getcache  -----------------------
                var obj = CacheHelper.Instance.Get(parameter);
                if (obj != null)
                    return (T)obj;
            }

            PropertyInfo p = FindPrimaryKeyType(type);
            var tableName = FindTableName(type);
            var sql = string.Format("select * from [{0}] where [{1}]={2}", tableName, p.Name, objectid);
            var value = LINQHelper.GetFirst<T>(sql);
            CacheHelper.Instance.Set(parameter, value);
            return value;
        }
        private static PropertyInfo FindPrimaryKeyType(Type returnType)
        {
            PropertyInfo[] properties = returnType.GetProperties();
            return (from p in properties let attributes = p.GetCustomAttributes(typeof(ColumnAttribute), false) where attributes.Cast<ColumnAttribute>().Any(attr => attr.IsPrimaryKey) select p).FirstOrDefault();
        }
        private static string FindTableName(Type type)
        {
            var attributes = (TableAttribute)type.GetCustomAttributes(typeof(TableAttribute), false)[0];
            return attributes.Name == null ? type.Name : attributes.Name.Replace("dbo.", "");
        }

        public static IList GetRange(IList list, int first, int end)
        {
            if (list.Count <= end || list.Count == 0)
                return list;

            IList newlist = new ArrayList();
            if (first >= list.Count)
                return newlist;
            for (int i = first; i < end; i++)
            {
                newlist.Add(list[i]);
            }
            return newlist;
        }
        public static void RemoveRange(ref IList list, int startIndex, int count)
        {
            while (count > 0 && list.Count > 0)
            {
                list.RemoveAt(startIndex);
                count--;
            }
        }
        public static int[] ToIntArray(string ids)
        {
            if (string.IsNullOrEmpty(ids)) return new int[0];
            return ids.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries).Select(n => Convert.ToInt32(n)).ToArray();
        }
        public static long[] ToBigIntArray(string ids)
        {
            if (string.IsNullOrEmpty(ids)) return new long[0];
            return ids.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries).Select(n => Convert.ToInt64(n)).ToArray();
        }

        public static bool EqualStr(string s1, string s2)
        {
            if (s1 == null || s2 == null) return false;
            return s1.ToLower().Equals(s2.ToLower());
        }

        public static bool ContainStr(string s1, string s2)
        {
            if (s1 == null || s2 == null) return false;
            return s1.ToLower().Contains(s2.ToLower());
        }
        public static bool StartsWithStr(string s1, string s2)
        {
            if (s1 == null || s2 == null) return false;
            return s1.ToLower().StartsWith(s2.ToLower());
        }
        public static bool IsAdminPage()
        {
            return HttpContext.Current.Request.Url.LocalPath.ToLower().IndexOf("/admin") >= 0;
        }

        public static string GetSafeName(string name)
        {
            return Core.Utils.Process.ConvertToSafeMarks(name).Trim().ToLower();
        }
        public static string GetSortName(string name)
        {
            return Core.Utils.Process.ConvertToSafeMarks(name).Replace("-", "").Trim().ToLower();
        }
        public static string GetSortNameFromSafeName(string safeName)
        {
            return safeName.Replace("-", "").Trim().ToLower();
        }

        public object Clone()
        {
            return MemberwiseClone();
        }
    }

    [Database]
    public class CmsDataContext : DataContext
    {
        private static readonly MappingSource MappingSource = new AttributeMappingSource();

        public CmsDataContext() :
            base(GetConnectionString, MappingSource)
        {
            CommandTimeout = 3600;
        }

        public CmsDataContext(string connection) :
            base(connection, MappingSource)
        {
            CommandTimeout = 3600;
        }

        #region Store Proceduce
        /// <summary>
        /// Save/Update Reference Table
        /// </summary>
        /// <param name="table"></param>
        /// <param name="columnKey"></param>
        /// <param name="keyValue"></param>
        /// <param name="columnRef"></param>
        /// <param name="refValue"></param>
        /// <returns></returns>
        [Function(Name = "ManyToManySave")]
        [ResultType(typeof(BaseObject))]
        public IMultipleResults ManyToManySave([Parameter(Name = "Table", DbType = "nvarchar(20)")] string table,
            [Parameter(Name = "ColumnKey", DbType = "nvarchar(20)")]string columnKey, [Parameter(Name = "KeyValue", DbType = "nvarchar(10)")]string keyValue,
            [Parameter(Name = "ColumnRef", DbType = "nvarchar(20)")]string columnRef, [Parameter(Name = "RefValue", DbType = "nvarchar(10)")]string refValue)
        {
            var method = MethodBase.GetCurrentMethod();
            if (method != null)
            {
                var result = ExecuteMethodCall(this, (MethodInfo)method, table, columnKey, keyValue, columnRef, refValue);
                return result != null ? (IMultipleResults)result.ReturnValue : null;
            }
            return null;
        }
        /// <summary>
        /// Save/Update Reference Table
        /// </summary>
        /// <param name="table"></param>
        /// <param name="columnKey"></param>
        /// <param name="keyValue"></param>
        /// <returns></returns>
        [Function(Name = "ManyToManyDelete")]
        [ResultType(typeof(BaseObject))]
        public IMultipleResults ManyToManyDelete([Parameter(Name = "Table", DbType = "nvarchar(20)")] string table,
            [Parameter(Name = "ColumnKey", DbType = "nvarchar(20)")]string columnKey, [Parameter(Name = "KeyValue", DbType = "nvarchar(10)")]string keyValue)
        {
            var method = MethodBase.GetCurrentMethod();
            if (method != null)
            {
                var result = ExecuteMethodCall(this, (MethodInfo)method, table, columnKey, keyValue);
                return result != null ? (IMultipleResults)result.ReturnValue : null;
            }
            return null;
        }

        [Function(Name = "FindLatestUpdate")]
        [ResultType(typeof(Book))]
        public IMultipleResults FindLatestUpdate(int max)
        {
            IExecuteResult result = ExecuteMethodCall(this, ((MethodInfo)(MethodInfo.GetCurrentMethod())), max);
            return ((IMultipleResults)(result.ReturnValue));
        }

        [Function(Name = "FindByView")]
        [ResultType(typeof(Book))]
        public IMultipleResults FindByView(int max)
        {
            IExecuteResult result = ExecuteMethodCall(this, ((MethodInfo)(MethodInfo.GetCurrentMethod())), max);
            return ((IMultipleResults)(result.ReturnValue));
        }
        #endregion

        #region Get Tables
        public Table<Book> Books
        {
            get { return GetTable<Book>(); }
        }
        public Table<HistoryType> HistoryTypes
        {
            get { return GetTable<HistoryType>(); }
        }
        public Table<BookByAuthor> BookByAuthors
        {
            get { return GetTable<BookByAuthor>(); }
        }

        public Table<Author> Authors
        {
            get { return GetTable<Author>(); }
        }
        public Table<Role> Roles
        {
            get { return GetTable<Role>(); }
        }

        public Table<Option> Options
        {
            get { return GetTable<Option>(); }
        }

        public Table<Comment> Comments
        {
            get { return GetTable<Comment>(); }
        }

        public Table<RoleUser> RoleUsers
        {
            get { return GetTable<RoleUser>(); }
        }

        public Table<Permission> Permissions
        {
            get { return GetTable<Permission>(); }
        }

        public Table<Layout> Layouts
        {
            get { return GetTable<Layout>(); }
        }

        public Table<Banner> Banners
        {
            get { return GetTable<Banner>(); }
        }

        public Table<PortalUser> PortalUsers
        {
            get { return GetTable<PortalUser>(); }
        }


        public Table<Webpart> Webparts
        {
            get { return GetTable<Webpart>(); }
        }

        public Table<BookOption> BookOptions
        {
            get { return GetTable<BookOption>(); }
        }

        public Table<BookType> BookTypes
        {
            get { return GetTable<BookType>(); }
        }

        public Table<WebpartDefinition> WebpartDefinitions
        {
            get { return GetTable<WebpartDefinition>(); }
        }

        public Table<WebpartPage> WebpartPages
        {
            get { return GetTable<WebpartPage>(); }
        }

        public Table<SimpleWebpart> SimpleWebparts
        {
            get { return GetTable<SimpleWebpart>(); }
        }

        public Table<Content> Contents
        {
            get { return GetTable<Content>(); }
        }

        public Table<BookCategory> BookCategories
        {
            get { return GetTable<BookCategory>(); }
        }

        public Table<Page> Pages
        {
            get { return GetTable<Page>(); }
        }

        public Table<Module> Modules
        {
            get { return GetTable<Module>(); }
        }

        public Table<PortalObject> PortalObjects
        {
            get { return GetTable<PortalObject>(); }
        }

        public Table<Category> Categories
        {
            get { return GetTable<Category>(); }
        }

        public Table<BannerGroup> BannerGroups
        {
            get { return GetTable<BannerGroup>(); }
        }


        #endregion

        private const string DataConnectString = "data@connectionstring";

        public static string GetConnectionString
        {
            get
            {
                if (HttpRuntime.Cache[DataConnectString] == null)
                {
                    HttpRuntime.Cache[DataConnectString] = ConfigurationSettings.AppSettings["connection-string"];
                }
                return HttpRuntime.Cache[DataConnectString].ToString();
            }
        }

        public static ITable GetTableByName(DataContext context, string tableName)
        {
            if (context == null)
            {
                throw new ArgumentNullException("context");
            }
            if (tableName == null)
            {
                throw new ArgumentNullException("tableName");
            }
            return (ITable)context.GetType().GetProperty(tableName).GetValue(context, null);
        }
    }
}

